home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / vim / src / mark.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  10KB  |  445 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Read the file "credits.txt" for a list of people who contributed.
  6.  * Read the file "uganda.txt" for copying and usage conditions.
  7.  */
  8.  
  9. /*
  10.  * mark.c: functions for setting marks and jumping to them
  11.  */
  12.  
  13. #include "vim.h"
  14. #include "globals.h"
  15. #include "proto.h"
  16.  
  17. /*
  18.  * This file contains routines to maintain and manipulate marks.
  19.  */
  20.  
  21. static struct filemark namedfm[NMARKS];        /* new marks with file nr */
  22.  
  23. /*
  24.  * setmark(c) - set named mark 'c' at current cursor position
  25.  *
  26.  * Returns OK on success, FAIL if no room for mark or bad name given.
  27.  */
  28.     int
  29. setmark(c)
  30.     int            c;
  31. {
  32.     int         i;
  33.  
  34.     if (islower(c))
  35.     {
  36.         i = c - 'a';
  37.         curbuf->b_namedm[i] = curwin->w_cursor;
  38.         return OK;
  39.     }
  40.     if (isupper(c))
  41.     {
  42.         i = c - 'A';
  43.         namedfm[i].mark = curwin->w_cursor;
  44.         namedfm[i].fnum = curbuf->b_fnum;
  45.         return OK;
  46.     }
  47.     return FAIL;
  48. }
  49.  
  50. /*
  51.  * setpcmark() - set the previous context mark to the current position
  52.  *                 and insert it into the jump list
  53.  */
  54.     void
  55. setpcmark()
  56. {
  57.     int i;
  58. #ifdef ROTATE
  59.     struct filemark tempmark;
  60. #endif
  61.  
  62.     curwin->w_prev_pcmark = curwin->w_pcmark;
  63.     curwin->w_pcmark = curwin->w_cursor;
  64.  
  65. #ifndef ROTATE
  66.     /*
  67.      * simply add the new entry at the end of the list
  68.      */
  69.     curwin->w_jumplistidx = curwin->w_jumplistlen;
  70. #else
  71.     /*
  72.      * If last used entry is not at the top, put it at the top by rotating
  73.      * the stack until it is (the newer entries will be at the bottom).
  74.      * Keep one entry (the last used one) at the top.
  75.      */
  76.     if (curwin->w_jumplistidx < curwin->w_jumplistlen)
  77.         ++curwin->w_jumplistidx;
  78.     while (curwin->w_jumplistidx < curwin->w_jumplistlen)
  79.     {
  80.         tempmark = curwin->w_jumplist[curwin->w_jumplistlen - 1];
  81.         for (i = curwin->w_jumplistlen - 1; i > 0; --i)
  82.             curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
  83.         curwin->w_jumplist[0] = tempmark;
  84.         ++curwin->w_jumplistidx;
  85.     }
  86. #endif
  87.  
  88.         /* only add new entry if it differs from the last one */
  89.     if (curwin->w_jumplistlen == 0 ||
  90.                 curwin->w_jumplist[curwin->w_jumplistidx - 1].mark.lnum !=
  91.                                                         curwin->w_pcmark.lnum ||
  92.                 curwin->w_jumplist[curwin->w_jumplistidx - 1].fnum !=
  93.                                                         curbuf->b_fnum)
  94.     {
  95.             /* if jumplist is full: remove oldest entry */
  96.         if (++curwin->w_jumplistlen > JUMPLISTSIZE)
  97.         {
  98.             curwin->w_jumplistlen = JUMPLISTSIZE;
  99.             for (i = 1; i < curwin->w_jumplistlen; ++i)
  100.                 curwin->w_jumplist[i - 1] = curwin->w_jumplist[i];
  101.             --curwin->w_jumplistidx;
  102.         }
  103.  
  104. #ifdef ARCHIE
  105.         /* Workaround for a bug in gcc 2.4.5 R2 on the Archimedes
  106.          * Should be fixed in 2.5.x.
  107.          */
  108.         curwin->w_jumplist[curwin->w_jumplistidx].mark.ptr = curwin->w_pcmark.ptr;
  109.         curwin->w_jumplist[curwin->w_jumplistidx].mark.col = curwin->w_pcmark.col;
  110. #else
  111.         curwin->w_jumplist[curwin->w_jumplistidx].mark = curwin->w_pcmark;
  112. #endif
  113.         curwin->w_jumplist[curwin->w_jumplistidx].fnum = curbuf->b_fnum;
  114.         ++curwin->w_jumplistidx;
  115.     }
  116. }
  117.  
  118. /*
  119.  * checkpcmark() - To change context, call setpcmark(), then move the current
  120.  *                   position to where ever, then call checkpcmark().  This
  121.  *                   ensures that the previous context will only be changed if
  122.  *                   the cursor moved to a different line. -- webb.
  123.  *                   If pcmark was deleted (with "dG") the previous mark is restored.
  124.  */
  125.     void
  126. checkpcmark()
  127. {
  128.     if (curwin->w_prev_pcmark.lnum != 0 &&
  129.             (curwin->w_pcmark.lnum == curwin->w_cursor.lnum ||
  130.             curwin->w_pcmark.lnum == 0))
  131.     {
  132.         curwin->w_pcmark = curwin->w_prev_pcmark;
  133.         curwin->w_prev_pcmark.lnum = 0;            /* Show it has been checked */
  134.     }
  135. }
  136.  
  137. /*
  138.  * move "count" positions in the jump list (count may be negative)
  139.  */
  140.     FPOS *
  141. movemark(count)
  142.     int count;
  143. {
  144.     FPOS        *pos;
  145.  
  146.     if (curwin->w_jumplistlen == 0)            /* nothing to jump to */
  147.         return (FPOS *)NULL;
  148.  
  149.     if (curwin->w_jumplistidx + count < 0 ||
  150.                         curwin->w_jumplistidx + count >= curwin->w_jumplistlen)
  151.         return (FPOS *)NULL;
  152.  
  153.     /*
  154.      * if first CTRL-O or CTRL-I command after a jump, add cursor position to list
  155.      */
  156.     if (curwin->w_jumplistidx == curwin->w_jumplistlen)
  157.     {
  158.         setpcmark();
  159.         --curwin->w_jumplistidx;        /* skip the new entry */
  160.     }
  161.  
  162.     curwin->w_jumplistidx += count;
  163.                                                 /* jump to other file */
  164.     if (curwin->w_jumplist[curwin->w_jumplistidx].fnum != curbuf->b_fnum)
  165.     {
  166.         if (buflist_getfile(curwin->w_jumplist[curwin->w_jumplistidx].fnum,
  167.                     curwin->w_jumplist[curwin->w_jumplistidx].mark.lnum, FALSE) == FAIL)
  168.             return (FPOS *)NULL;
  169.         curwin->w_cursor.col = curwin->w_jumplist[curwin->w_jumplistidx].mark.col;
  170.         pos = (FPOS *)-1;
  171.     }
  172.     else
  173.         pos = &(curwin->w_jumplist[curwin->w_jumplistidx].mark);
  174.     return pos;
  175. }
  176.  
  177. /*
  178.  * getmark(c) - find mark for char 'c'
  179.  *
  180.  * Return pointer to FPOS if found
  181.  *        NULL if no such mark.
  182.  *        -1 if mark is in other file (only if changefile is TRUE)
  183.  */
  184.     FPOS *
  185. getmark(c, changefile)
  186.     int            c;
  187.     int            changefile;
  188. {
  189.     FPOS    *posp;
  190.     static    FPOS    pos_copy;
  191.  
  192.     posp = NULL;
  193.     if (c == '\'' || c == '`')            /* previous context mark */
  194.     {
  195.         pos_copy = curwin->w_pcmark;    /* need to make a copy because b_pcmark */
  196.         posp = &pos_copy;                /*   may be changed soon */
  197.     }
  198.     else if (c == '[')                    /* to start of previous operator */
  199.     {
  200.         if (curbuf->b_startop.lnum > 0 &&
  201.                         curbuf->b_startop.lnum <= curbuf->b_ml.ml_line_count)
  202.             posp = &(curbuf->b_startop);
  203.     }
  204.     else if (c == ']')                    /* to end of previous operator */
  205.     {
  206.         if (curbuf->b_endop.lnum > 0 &&
  207.                         curbuf->b_endop.lnum <= curbuf->b_ml.ml_line_count)
  208.             posp = &(curbuf->b_endop);
  209.     }
  210.     else if (islower(c))                /* normal named mark */
  211.         posp = &(curbuf->b_namedm[c - 'a']);
  212.     else if (isupper(c))                /* named file mark */
  213.     {
  214.         c -= 'A';
  215.         posp = &(namedfm[c].mark);
  216.         if (namedfm[c].fnum != curbuf->b_fnum &&
  217.                                     namedfm[c].mark.lnum != 0 && changefile)
  218.         {
  219.             if (buflist_getfile(namedfm[c].fnum, namedfm[c].mark.lnum, TRUE) == OK)
  220.             {
  221.                 curwin->w_cursor.col = namedfm[c].mark.col;
  222.                 posp = (FPOS *)-1;
  223.             }
  224.         }
  225.     }
  226.     return posp;
  227. }
  228.  
  229. /*
  230.  * clrallmarks() - clear all marks in the buffer 'buf'
  231.  *
  232.  * Used mainly when trashing the entire buffer during ":e" type commands
  233.  */
  234.     void
  235. clrallmarks(buf)
  236.     BUF        *buf;
  237. {
  238.     static int             i = -1;
  239.  
  240.     if (i == -1)        /* first call ever: initialize */
  241.         for (i = 0; i < NMARKS; i++)
  242.             namedfm[i].mark.lnum = 0;
  243.  
  244.     for (i = 0; i < NMARKS; i++)
  245.         buf->b_namedm[i].lnum = 0;
  246.     buf->b_startop.lnum = 0;        /* start/end op mark cleared */
  247.     buf->b_endop.lnum = 0;
  248. }
  249.  
  250. /*
  251.  * get name of file from a filemark
  252.  */
  253.     char_u *
  254. fm_getname(fmark)
  255.     struct filemark *fmark;
  256. {
  257.     char_u        *name;
  258.  
  259.     if (fmark->fnum != curbuf->b_fnum)                /* not current file */
  260.     {
  261.         name = buflist_nr2name(fmark->fnum);
  262.         if (name == NULL)
  263.             return (char_u *)"-unknown-";
  264.         return name;
  265.     }
  266.     return (char_u *)"-current-";
  267. }
  268.  
  269. /*
  270.  * print the marks (use the occasion to update the line numbers)
  271.  */
  272.     void
  273. domarks()
  274. {
  275.     int            i;
  276.     char_u        *name;
  277.  
  278.     gotocmdline(TRUE, NUL);
  279.     msg_outstr((char_u *)"\nmark line  file\n");
  280.     for (i = 0; i < NMARKS; ++i)
  281.     {
  282.         if (curbuf->b_namedm[i].lnum != 0)
  283.         {
  284.             sprintf((char *)IObuff, " %c %5ld\n", i + 'a',
  285.                                                 curbuf->b_namedm[i].lnum);
  286.             msg_outstr(IObuff);
  287.         }
  288.         flushbuf();
  289.     }
  290.     for (i = 0; i < NMARKS; ++i)
  291.     {
  292.         if (namedfm[i].mark.lnum != 0)
  293.         {
  294.             name = fm_getname(&namedfm[i]);
  295.             if (name == NULL)        /* file name not available */
  296.                 continue;
  297.  
  298.             sprintf((char *)IObuff, " %c %5ld  %s\n",
  299.                 i + 'A',
  300.                 namedfm[i].mark.lnum,
  301.                 name);
  302.             msg_outstr(IObuff);
  303.         }
  304.         flushbuf();                /* show one line at a time */
  305.     }
  306.     msg_end();
  307. }
  308.  
  309. /*
  310.  * print the jumplist
  311.  */
  312.     void
  313. dojumps()
  314. {
  315.     int            i;
  316.     char_u        *name;
  317.  
  318.     gotocmdline(TRUE, NUL);
  319.     msg_outstr((char_u *)"\n jump line  file\n");
  320.     for (i = 0; i < curwin->w_jumplistlen; ++i)
  321.     {
  322.         if (curwin->w_jumplist[i].mark.lnum != 0)
  323.         {
  324.             name = fm_getname(&curwin->w_jumplist[i]);
  325.             if (name == NULL)        /* file name not available */
  326.                 continue;
  327.  
  328.             sprintf((char *)IObuff, "%c %2d %5ld  %s\n",
  329.                 i == curwin->w_jumplistidx ? '>' : ' ',
  330.                 i + 1,
  331.                 curwin->w_jumplist[i].mark.lnum,
  332.                 name);
  333.             msg_outstr(IObuff);
  334.         }
  335.         flushbuf();
  336.     }
  337.     if (curwin->w_jumplistidx == curwin->w_jumplistlen)
  338.         msg_outstr((char_u *)">\n");
  339.     msg_end();
  340. }
  341.  
  342. /*
  343.  * adjust marks between line1 and line2 (inclusive) to move 'inc' lines
  344.  * If 'inc' is MAXLNUM the mark is made invalid.
  345.  */
  346.     void
  347. mark_adjust(line1, line2, inc)
  348.     linenr_t    line1;
  349.     linenr_t    line2;
  350.     long        inc;
  351. {
  352.     int            i;
  353.     int            fnum = curbuf->b_fnum;
  354.     linenr_t    *lp;
  355.     WIN            *win;
  356.  
  357. /* named marks, lower case and upper case */
  358.     for (i = 0; i < NMARKS; i++)
  359.     {
  360.         lp = &(curbuf->b_namedm[i].lnum);
  361.         if (*lp >= line1 && *lp <= line2)
  362.         {
  363.             if (inc == MAXLNUM)
  364.                 *lp = 0;
  365.             else
  366.                 *lp += inc;
  367.         }
  368.         if (namedfm[i].fnum == fnum)
  369.         {
  370.             lp = &(namedfm[i].mark.lnum);
  371.             if (*lp >= line1 && *lp <= line2)
  372.             {
  373.                 if (inc == MAXLNUM)
  374.                     *lp = 0;
  375.                 else
  376.                     *lp += inc;
  377.             }
  378.         }
  379.     }
  380.  
  381. /* previous context mark */
  382.     lp = &(curwin->w_pcmark.lnum);
  383.     if (*lp >= line1 && *lp <= line2)
  384.     {
  385.         if (inc == MAXLNUM)
  386.             *lp = 0;
  387.         else
  388.             *lp += inc;
  389.     }
  390.  
  391. /* previous pcmark */
  392.     lp = &(curwin->w_prev_pcmark.lnum);
  393.     if (*lp >= line1 && *lp <= line2)
  394.     {
  395.         if (inc == MAXLNUM)
  396.             *lp = 0;
  397.         else
  398.             *lp += inc;
  399.     }
  400.  
  401. /* quickfix marks */
  402.     qf_mark_adjust(line1, line2, inc);
  403.  
  404. /* jumplist marks */
  405.     for (win = firstwin; win != NULL; win = win->w_next)
  406.     {
  407.         for (i = 0; i < win->w_jumplistlen; ++i)
  408.             if (win->w_jumplist[i].fnum == fnum)
  409.             {
  410.                 lp = &(win->w_jumplist[i].mark.lnum);
  411.                 if (*lp >= line1 && *lp <= line2)
  412.                 {
  413.                     if (inc == MAXLNUM)
  414.                         *lp = 0;
  415.                     else
  416.                         *lp += inc;
  417.                 }
  418.             }
  419.         /*
  420.          * also adjust the line at the top of the window and the cursor position
  421.          * for windows with the same buffer.
  422.          */
  423.         if (win != curwin && win->w_buffer == curbuf)
  424.         {
  425.             if (win->w_topline >= line1 && win->w_topline <= line2)
  426.             {
  427.                 if (inc == MAXLNUM)        /* topline is deleted */
  428.                     win->w_topline = line1;
  429.                 else                    /* keep topline on the same line */
  430.                     win->w_topline += inc;
  431.             }
  432.             if (win->w_cursor.lnum >= line1 && win->w_cursor.lnum <= line2)
  433.             {
  434.                 if (inc == MAXLNUM)        /* line with cursor is deleted */
  435.                 {
  436.                     win->w_cursor.lnum = line1;
  437.                     win->w_cursor.col = 0;
  438.                 }
  439.                 else                    /* keep cursor on the same line */
  440.                     win->w_cursor.lnum += inc;
  441.             }
  442.         }
  443.     }
  444. }
  445.